import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

/// 底部输出面板，用于显示运行 / 调试的日志信息。
///
/// 特性：
/// 1. 固定高度（默认 180 px）；
/// 2. 将所有日志拼接成单一文本块，通过 [SelectableText] 渲染，支持跨行选择和复制；
/// 3. 使用 `BoxConstraints(minWidth: double.infinity)` 避免文本被居中；
/// 4. 新日志到来时自动滚动到底部（支持用户手动浏览历史，带防抖和恢复机制）。
class OutputPanel extends StatefulWidget {
  const OutputPanel({
    super.key,
    this.height = 180,
    required this.logs,
    this.autoScroll = true,
  });

  /// 面板高度，默认 180。
  final double height;

  /// 日志数据源。
  ///
  /// 外部通过 [ValueListenable] 提供日志行列表，
  /// 面板监听其变化并实时刷新。
  final ValueListenable<List<String>> logs;

  /// 是否在新日志到来时自动滚动到底部。
  final bool autoScroll;

  @override
  State<OutputPanel> createState() => _OutputPanelState();
}

class _OutputPanelState extends State<OutputPanel> {
  final ScrollController _scrollCtrl = ScrollController();

  // -------- 自动滚动相关状态 --------
  static const double _autoScrollThresholdPx = 40.0; // 距离底部容忍阈值
  bool _userHolding = false;        // 用户是否在查看历史（非底部）
  bool _queuedAutoScroll = false;   // 是否已安排一次滚动（防抖）

  @override
  void initState() {
    super.initState();
    _scrollCtrl.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollCtrl.removeListener(_onScroll);
    _scrollCtrl.dispose();
    super.dispose();
  }

  /// 滚动监听：判断用户是否停留在底部。
  void _onScroll() {
    if (!_scrollCtrl.hasClients) return;

    final atBottom =
        _scrollCtrl.position.maxScrollExtent - _scrollCtrl.offset <=
            _autoScrollThresholdPx;

    _userHolding = !atBottom;

    // 用户重新滚到最底 → 立即恢复自动跟随
    if (atBottom && !_queuedAutoScroll) {
      _maybeAutoScroll(force: true);
    }
  }

  /// 在日志更新后尝试自动滚动到底。
  ///
  /// - [force] 表示强制执行（即使用户在浏览历史）。
  void _maybeAutoScroll({bool force = false}) {
    if (!mounted || !_scrollCtrl.hasClients) return;
    if (!(widget.autoScroll && (!_userHolding || force))) return;

    _queuedAutoScroll = true;
    // 等待下一帧布局完成后再滚动，避免位置不准确
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted || !_scrollCtrl.hasClients) return;
      _scrollCtrl.jumpTo(_scrollCtrl.position.maxScrollExtent);
      _queuedAutoScroll = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: widget.height,
      child: ClipRect(
        child: ValueListenableBuilder<List<String>>(
          valueListenable: widget.logs,
          builder: (_, lines, _) {
            if (lines.isEmpty) {
              return const Center(
                child: Text(
                  'No output yet…',
                  style: TextStyle(fontSize: 13, color: Colors.black54),
                ),
              );
            }

            // 将日志拼接为单一文本块（利于跨行复制）
            final text = lines.join('\n');

            // 每次日志变化都尝试滚动
            _maybeAutoScroll();

            return Scrollbar(
              controller: _scrollCtrl,
              thumbVisibility: true,
              child: SingleChildScrollView(
                controller: _scrollCtrl,
                padding:
                const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                child: ConstrainedBox(
                  constraints: const BoxConstraints(minWidth: double.infinity),
                  child: SelectableText(
                    text,
                    style: const TextStyle(
                      fontSize: 13,
                      height: 1.35,
                      fontFamily: 'JetBrains Mono',
                    ),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}
